﻿using System.Collections.Generic;
using TgcViewer.Utils.TgcSceneLoader;
using TgcViewer.Utils.TgcGeometry;
using Microsoft.DirectX;
using TgcViewer.Utils;

namespace AlumnoEjemplos.zanellaSports
{
    public class General
    {
        /// <summary> 
        /// Devuelve el ángulo entre dos vectores en R3 cuyas componentes en el eje y son nulas
        /// </summary>
        /// <returns>Angulo en radianes</returns>
        public static float anguloEntreVectores(Vector3 v1, Vector3 v2) //Solo en el plano XZ        
        {
            return (FastMath.Acos((v1.X * v2.X + v1.Z * v2.Z) / (moduloVector2(new Vector2(v1.X, v1.Z)) * moduloVector2(new Vector2(v2.X, v2.Z)))));
        }

        /// <summary>
        /// Devuelve el ángulo (radianes) entre dos versores en R3 cuyas componentes en el eje Y son nulas
        /// </summary>
        /// <returns>Angulo en radianes</returns>
        public static float anguloEntreVersores(Vector3 v1, Vector3 v2) //Solo en el plano XZ        
        {
            return (FastMath.Acos(v1.X * v2.X + v1.Z * v2.Z));
        }

        /// <summary>
        /// Devuelve el modulo de un Vector3
        /// </summary>
        public static float moduloVector3(Vector3 v)
        {
            float modulo = v.Length();
            return modulo > 0 ? modulo : -modulo;
        }

        /// <summary>
        /// Devuelve el modulo de un Vector2
        /// </summary>
        public static float moduloVector2(Vector2 v)
        {
            float modulo = v.Length();
            return modulo > 0 ? modulo : -modulo;
        }

        /// <summary>
        /// Devuelve un nuevo Vector3 a partir de rotar el dado (con respecto al origen) un angulo en radianes
        /// </summary>
        public static Vector3 RotarVectorY(Vector3 vector, float angle)
        {
            //Cambio el signo del angulo para que gire en sentido horario con angulos positivos
            angle = -angle;

            //Almacena la posision inicial
            float posX = vector.X;
            float posZ = vector.Z;

            //Calcula la nueva posicion
            posX = (posX * FastMath.Cos(angle)) - (posZ * FastMath.Sin(angle));
            posZ = (posZ * FastMath.Cos(angle)) + (posX * FastMath.Sin(angle));

            //Devuelve el vector rotado
            return (new Vector3(posX, vector.Y, posZ));
        }
    }

    public class Lists
    {
        /// <summary>
        /// Elimina los duplicados de una lista de strings
        /// </summary>
        public static List<string> removeDuplicates(List<string> inputList)
        {
            Dictionary<string, int> uniqueStore = new Dictionary<string, int>();
            List<string> finalList = new List<string>();

            foreach (string currValue in inputList)
            {
                if (!uniqueStore.ContainsKey(currValue))
                {
                    uniqueStore.Add(currValue, 0);
                    finalList.Add(currValue);

                }
            }
            return finalList;
        }

        /// <summary>
        /// Elimina los duplicados de una lista de TgcMesh
        /// </summary>
        public static List<TgcMesh> removeDuplicates(List<TgcMesh> inputList)
        {
            Dictionary<TgcMesh, int> uniqueStore = new Dictionary<TgcMesh, int>();
            List<TgcMesh> finalList = new List<TgcMesh>();

            foreach (TgcMesh currValue in inputList)
            {
                if (!uniqueStore.ContainsKey(currValue))
                {
                    uniqueStore.Add(currValue, 0);
                    finalList.Add(currValue);

                }
            }
            return finalList;
        }
    }

    public class Vertex
    {
        //Identificador
        public string id;

        //Ubicación (2d)
        public float X;
        public float Y;

        //Vertice que precede a este en la coneccion del camino optimo
        public Vertex anterior;

        //Distancia optima hallada desde el vertice de origen hasta este vertice
        public float distanciaDesdeComienzo;

        //Construcutor
        public Vertex(string id, float X, float Y)
        {
            this.id = id;
            this.X = X;
            this.Y = Y;

            this.anterior = null;
            this.distanciaDesdeComienzo = int.MaxValue;
        }

        //Constructor empty
        public Vertex()
        {
            this.id = "null";
            this.X = 0;
            this.Y = 0;

            this.anterior = null;
            this.distanciaDesdeComienzo = int.MaxValue;
        }

        public override string ToString()
        {
            return (id + " - " + X.ToString() + " – " + Y.ToString());
        }
    }

    public class Edge
    {
        //Vertice inicial
        public Vertex Vertex1;

        //Vertice final
        public Vertex Vertex2;

        //Distancia entre vertices
        public float Distance;

        //Contructor
        public Edge(Vertex Vertex1, Vertex Vertex2)
        {
            this.Vertex1 = Vertex1;
            this.Vertex2 = Vertex2;

            //Calculo la distancia y la asigno
            this.Distance = (new Vector2(Vertex2.X - Vertex1.X, Vertex2.Y - Vertex1.Y)).Length();
        }

    }
}